package com.iflytek.application.common.resttemplate;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Type;
import java.net.URI;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by guanxf on 2016-03-04.
 */
@RequiredArgsConstructor
public class ApplicationRestTemplate extends RestTemplate implements ApplicationRestOperation {
    private final RequestCallback requestCallback;
    @Override
    public void delete(String url, Object... urlVariables) throws RestClientException {
        execute(url, HttpMethod.DELETE, requestCallback, null, urlVariables);
    }

    @Override
    public void delete(String url, Map<String, ?> urlVariables) throws RestClientException {
        execute(url, HttpMethod.DELETE, requestCallback, null, urlVariables);
    }

    @Override
    public void delete(URI url) throws RestClientException {
        execute(url, HttpMethod.DELETE, requestCallback, null);
    }

    protected <T> RequestCallback acceptHeaderRequestCallback(Class<T> clazz) {
        RequestCallback callback = super.acceptHeaderRequestCallback(clazz);
        return new CompositeRequestCallback(Arrays.asList(callback, requestCallback));
    }

    protected <T> RequestCallback httpEntityCallback(Object requestBody) {
        RequestCallback callback = super.httpEntityCallback(requestBody);
        return new CompositeRequestCallback(Arrays.asList(callback, requestCallback));
    }
    
    protected <T> RequestCallback httpEntityCallback(Object requestBody, Type clazz) {
        RequestCallback callback = super.httpEntityCallback(requestBody, clazz);
        return new CompositeRequestCallback(Arrays.asList(callback, requestCallback));
    }

    @Override
    public <T> T getForObject(String url, Class<T> clazz, Map<String, Object> queryMap, Pageable pageable, Object... uriVariables) throws RestClientException{
        url = this.urlQueryAndPage(url, queryMap, pageable);
        return super.getForObject(url, clazz, uriVariables);
    }

    @Override
    public <T> T getForObject(String url, Class<T> clazz, Map<String, Object> queryMap, Pageable pageable, Map<String, ?> uriVariables) throws RestClientException{
        url = this.urlQueryAndPage(url, queryMap, pageable);
        return super.getForObject(url, clazz, uriVariables);
    }

    @Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> clazz, Map<String, Object> queryMap, Pageable pageable, Object... uriVariables) throws RestClientException{
        url = this.urlQueryAndPage(url, queryMap, pageable);
        return super.getForEntity(url, clazz, queryMap, pageable, uriVariables);
    }

    @Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> clazz, Map<String, Object> queryMap, Pageable pageable, Map<String, ?> uriVariables) throws RestClientException{
        url = this.urlQueryAndPage(url, queryMap, pageable);
        return super.getForEntity(url, clazz, uriVariables);
    }


    /**
     * 封装可变查询参数的URL
     * @param url
     * @param queryMap
     * @param pageable
     * @return
     */
    private String urlQueryAndPage(String url, Map<String, Object> queryMap, Pageable pageable) {
        if(!url.contains("?")) url += "?"; else url += "&";
        if(null != queryMap){
            for(Map.Entry<String, Object> entry : queryMap.entrySet())
                if(null != entry.getKey() && null != entry.getValue()){
                    url += entry.getKey() + "=" + entry.getValue() + "&";
                }
        }
        if(null != pageable){
            url += "page=" + pageable.getPageNumber() + "&size=" + pageable.getPageSize();
            if(null != pageable.getSort() && null != pageable.getSort().iterator()){
                Iterator<Sort.Order> orderIterator = pageable.getSort().iterator();
                while (orderIterator.hasNext()){
                    Sort.Order order = orderIterator.next();
                    url += "&sort=" + order.getProperty() + "," + order.getDirection();
                }
            }
        }
        return url;
    }
}
